//
//  AppDelegate.m
//  iTunesTopSongs
//
//  Created by 云天 李 on 12-2-13.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#import "AppDelegate.h"
#import "TopSongsViewController.h"

@implementation AppDelegate

@synthesize window = _window;
@synthesize managedObjectContext = __managedObjectContext;
@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
@synthesize persistentStorePath = __persistentStorePath;

@synthesize navigationController = _navigationController;
@synthesize topSongsViewController = _topSongsViewController;

@synthesize operationQueue = _operationQueue;
@synthesize importer = _importer;

// 存储在用户缺省存储（NSUserDefaults）中更新时间的标识符
static NSString * const kLastStoreUpdateKey = @"LastStoreUpdate";

// 获取排行榜的 RSS 种子的更新频率，单位：秒
static NSTimeInterval const kRefreshTimeInterval = 3600;

// RSS 种子中的歌曲数量
static NSUInteger const kImportSize = 100;

- (void)dealloc
{
	[_window release];
	[__managedObjectContext release];
	[__persistentStoreCoordinator release];
	[__persistentStorePath release];
	[_navigationController release];
	[_topSongsViewController release];
	[_operationQueue release];
	[_importer release];
	
    [super dealloc];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.

	// 检查NSUserDefaults中的数据是否需要更新
    NSDate *lastUpdate = [[NSUserDefaults standardUserDefaults] objectForKey:kLastStoreUpdateKey];
    if (lastUpdate == nil || -[lastUpdate timeIntervalSinceNow] > kRefreshTimeInterval) {
        
        // 如果需要更新，则将旧文件移除（如果旧文件存在的话。注意第一次运行程序时，存储文件是不存在的）
        if ([[NSFileManager defaultManager] fileExistsAtPath:self.persistentStorePath]) {
            NSError *error = nil;
            BOOL oldStoreRemovalSuccess = [[NSFileManager defaultManager] removeItemAtPath:self.persistentStorePath error:&error];
            NSAssert3(oldStoreRemovalSuccess, @"Unhandled error adding persistent store in %s at line %d: %@", __FUNCTION__, __LINE__, [error localizedDescription]);
        }
        
        // 创建一个iTunesRSSImporter（NSOperation的一个子类）实例，下载数据并存储在 Core Data 持久化存储中。 
        self.importer = [[[iTunesRSSImporter alloc] init] autorelease];
        self.importer.delegate = self;
        // 设置持久化存储协调器
        self.importer.persistentStoreCoordinator = self.persistentStoreCoordinator;
        self.importer.iTunesURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://ax.phobos.apple.com.edgesuite.net/WebObjects/MZStore.woa/wpa/MRSS/newreleases/limit=%d/rss.xml", kImportSize]];
        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
        
        // 把 iTunesRSSImporter加入到后台操作队列，启用新线程进行处理
        [self.operationQueue addOperation:self.importer];
    }
	// 初始化主视图（歌曲排行榜）
	self.topSongsViewController = [[[TopSongsViewController alloc] initWithNibName:@"TopSongsViewController" bundle:nil] autorelease];
	// 设置主视图的托管对象上下文
	self.topSongsViewController.managedObjectContext = self.managedObjectContext;
	
	// 显示出来
	self.navigationController = [[[UINavigationController alloc] initWithRootViewController:self.topSongsViewController] autorelease];
	self.window.rootViewController = self.navigationController;
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
	/*
	 Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
	 Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
	 */
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
	/*
	 Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
	 If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
	 */
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
	/*
	 Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
	 */
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
	/*
	 Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
	 */
}

- (void)applicationWillTerminate:(UIApplication *)application
{
}

#pragma mark - Operation Queue
// 后台操作队列，会开启一个新线程处理
- (NSOperationQueue *)operationQueue {
    if (_operationQueue == nil)
	{
        _operationQueue = [[NSOperationQueue alloc] init];
    }
    return _operationQueue;
}

#pragma mark - Core Data stack

/**
 返回应用程序的托管对象上下文
 如果上下文不存在，则创建一个，并关联持久化存储协调器。
 */
- (NSManagedObjectContext *)managedObjectContext
{
    if (__managedObjectContext == nil)
    {
		NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
		if (coordinator != nil)
		{
			__managedObjectContext = [[NSManagedObjectContext alloc] init];
			[__managedObjectContext setPersistentStoreCoordinator:coordinator];
		}
    }
    
    return __managedObjectContext;
}

/**
 返回应用程序的持久化存储协调器
 如果持久化存储协调器不存在，则创建一个，并关联持久化存储。
 */
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (__persistentStoreCoordinator == nil)
    {
		
		NSURL *storeUrl = [NSURL fileURLWithPath:self.persistentStorePath];
		
		NSError *error = nil;
		__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:nil]];
		NSPersistentStore *persistentStore = [__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error];
		NSAssert3(persistentStore != nil, @"Unhandled error adding persistent store in %s at line %d: %@", __FUNCTION__, __LINE__, [error localizedDescription]);
    }
    return __persistentStoreCoordinator;
}

/*
 返回应用程序的持久化存储
 */
- (NSString *)persistentStorePath {
    if (__persistentStorePath == nil)
	{
        NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
        __persistentStorePath = [[documentsDirectory stringByAppendingPathComponent:@"iTunesTopSongs.sqlite"] retain];
    }
    return __persistentStorePath;
}

#pragma mark <iTunesRSSImporterDelegate> Implementation

// 此方法将被第二线程和主线程调用。
// 这个方法可以分成2个方法，如下面的importerDidFinishParsingData:和handleImportCompletion
// 不过这里合并成一个方法。
// 
// 第二线程调用此方法时，方法先做了一个判断，发现不是主线程，就转到if的else块，调用主线程的importerDidSave:方法
// 于是此方法再次被调用。方法继续做判断，发现在主线程内，就进入if的第一个块。
// 请读者试试改一下handleImportCompletion方法和handleImportError:方法，用这种方式实现。
- (void)importerDidSave:(NSNotification *)saveNotification {
    if ([NSThread isMainThread])
	{
        [self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
		
		// 每保存20首歌曲后，就会将再次获取Core Data中的歌曲信息，并显示出来
        [self.topSongsViewController fetch];
    }
	else
	{
        [self performSelectorOnMainThread:@selector(importerDidSave:) withObject:saveNotification waitUntilDone:NO];
    }
}

// 主线程方法。排行榜下载完毕，并保存到Core Data后的一些处理。
- (void)handleImportCompletion {
    // 记录排行榜的最后一次保存到Core Data的时间。程序每次运行时，用来判断是否要更新排行榜。
    [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:kLastStoreUpdateKey];
	
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    self.importer = nil;
}

// 实现iTunesRSSImporterDelegate代理中的方法，被第二线程调用。
- (void)importerDidFinishParsingData:(iTunesRSSImporter *)importer {
    [self performSelectorOnMainThread:@selector(handleImportCompletion) withObject:nil waitUntilDone:NO];
}

// 主线程方法。用于处理下载排行榜时产生的错误。
- (void)handleImportError:(NSError *)error {
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    self.importer = nil;
	
    // 错误处理......
    NSAssert3(NO, @"Unhandled error in %s at line %d: %@", __FUNCTION__, __LINE__, [error localizedDescription]);
}

// 实现iTunesRSSImporterDelegate代理中的方法，被第二线程调用。
- (void)importer:(iTunesRSSImporter *)importer didFailWithError:(NSError *)error {
    [self performSelectorOnMainThread:@selector(handleImportError:) withObject:error waitUntilDone:NO];
}

@end
